USBメモリ ルートディレクトリ
ファイル検索
(→プロジェクトファイル(Harmony Ver.2.04版 ) ダウンロード)
USBメモリのルートディレクトリにあるファイルの数 及びファイル名を検索する例を紹介します。
<仕様>
・USBメモリのルートディレクトリにあるファイルの総数をカウントしてキャラクタ液晶に表示する。
・USBメモリのルートディレクトリにあるファイルの名称をすべて表示する。
・ファイル名の表示はキャラクタ液晶 及び TeraTerm(PCとの接続はUART)とする。
・キャラクタ液晶への ファイル数 及び各ファイル名表示は 2~3sec の間隔をあけて順次1項目づつ表示のこと
・ファイルは押しボタンスイッチ(SW2)をクリックすることにより 開いているファイルを閉じて次のファイルをオープンするかたちで
スキップできること。
またスキップ後、新たにオープンしたファイル名を 閉じたファイル名の代わりにキャラクタ液晶に表示のこと。
・また、他の押しボタンスイッチ(SW1)をクリックすることにより ファイルを オープン/クローズできること。
尚、ファイルがオープンしたらLEDを点灯し、クローズしたら消灯すること。
<外観> PIC32MZ評価ボード(→購入方法)を使った実験品の外観です。
<動作結果>(→ 動画 : 1080pのHD動画を見ることができます。)
キャラクタ液晶 | |||
項目 | 画面 | 備考 | |
➀ | ルートディレクトリにある ファイル総数 |
![]() |
|
➁ | ファイル名表示(例) | 8.3形式ファイル名 | |
ロングファイル名 |
Tera Term画面 | |
ルートディレクトリにある 全ファイル一覧 |
![]() |
<解説>記載してある内容は要点だけです。 詳細はプロジェクトファイルを精読願います。
(以下は、Harmony v2.04 をもとに作成しています。最新のバージョンは異なることがあるかもしれませんので注意してください。)
■MHCの設定
■Options
■ Pin Settins
■キャラクタ液晶表示ライブラリの追加要領
キャラクタ液晶表示のライブラリ 1lcd_lib_XC32.h と 1lcd_lib_XC32.cを main.cと同じフォルダにコピーして、プロジェクトに追加します。
(使い方 → キャラクタ液晶表示方法 参照)
プロジェクトへの追加は以下のようにします。
■app.h に青字部分を追加します。
➀ 取り扱うファイル数の最大を80個に設定します。
#define DISK_MAX_FILES 80
➁ファイルを最大64バイトのフルパス付ファイルで扱います。 このフルパスのファイルと Harmonyのファイルが標準で持っている
ファイルの特性を保持しているSYS_FS_FSTAT構造体をメンバーにもつDISK_FILE_NODE構造体を宣言します。 プログラムの
なかではこのDISK_FILE_NODE構造体のインスタンスをファイルとして扱います。
typedef struct{
SYS_FS_FSTAT fstat;
char path[64];
}DISK_FILE_NODE;
typedef struct{
char path[64]; // at most 64 bytes long
}DISK_FILE_PATH;
以下、 app.h
■ app,c に青字部を追加します。
➀インクルードファイルを追加します。stdio.hがないと、sprintf( )がコンパイラのバージョンによってコンパイルで警告となることが
あります。
#include "stdio.h"
➁所要の変数、ファイルハンドル、構造体のインスタンスなどの宣言 及び定義を行います。
int delay_Clock = 200000000; //システムクロック:200MHz
char Buf[32];
char Buf2[32]; //液晶上段、下段のバッファを分ける //下段が16文字を超えると上段の表示に影響がある
int BtnEvent[2];
int totalFiles;
int ysPlay;
SYS_FS_HANDLE ys_fileHandle;
SYS_FS_HANDLE ys_dirHandle;
SYS_FS_FSTAT ys_dirstat; //ファイル・ディレクトリ構造体
static DISK_FILE_NODE rootNode;
static DISK_FILE_PATH FilesTable[DISK_MAX_FILES];
char str_FileName[64]; //ファイル名
int Num_File = 1;
③USBの接続状態に係る列挙名、USBメモリ読み込み状態に係る列挙名、ボタンスイッチの状態に係る列挙名などを
定義します。
enum{ //USBの状態に係る列挙名
USB_STATE_OPEN_HOST_LAYER,
USB_STATE_WAIT_FOR_HOST_ENABLE,
USB_STATE_DEVICE_CONNECTED,
USB_STATE_WAIT_FOR_DEVICE_ATTACH,
USB_STATE_UNMOUNT_DISK
}UsbState;
enum{ //USBディスクの状態に係る列挙名
DISK_STATE_INIT,
DISK_STATE_SCAN_FINISHED,
DISK_STATE_OPEN_FIRST_FILE,
DISK_STATE_SCANNING,
DISK_STATE_RUNNING,
DISK_STATE_REMOVED,
DISK_STATE_NO_FILES,
}DiskState;
enum {
APP_OPE_PAUSE_REPLAY = 1,
APP_OPE_SKIP,
}AppBtn;
enum
{
PLAYER_CMD_STOP,
PLAYER_CMD_PLAY,
PLAYER_CMD_NEXT_FILE,
}PlayerCommand;
④関数のプロトタイプ宣言をおこないます。
//関数のプロトタイプ宣言
void DISK_NextTrack(void);
void DISK_CloseTruck (SYS_FS_HANDLE fileHandle);
void DISK_OpenTrack ( const char *fname );
bool ys_FileType83(char *myFileName);
void DISK_TraverseAllFiles(DISK_FILE_NODE node);
void APP_SYSFSEventHandler(SYS_FS_EVENT event, void * eventData, uintptr_t
context);
USB_HOST_EVENT_RESPONSE APP_USBHostEventHandler (USB_HOST_EVENT event,
void * eventData, uintptr_t context);
void USB_Connection_Tasks(void);
void DISK_Tasks(void);
void APP_PlayerTask(void);
bool APP_PlayerCommand (int cmd);
void APP_OnButtonEvent(uint8_t button, bool bButtonClosed, int32_t repeatCount);
void APP_BtnTask(void);
⑤delay_us( )、delay_ms( ) という NOPを使った 1μsec 、1msec単位の遅延関数をつくります。HarmonyではSYS_Tasks
( )の中で
長い時間の遅延をつかうとその遅延時間だけタスクがそこで止まってしまいますので注意して使う必要があります。
void delay_us(volatile unsigned int usec) //1μsec遅延
{
volatile int count;
count = (int)(delay_Clock/20000000)*usec;
……
……
⑥UARTでTeraTermに文字を送信する関数です。
void Write_Byte(char chr) //1バイト送信関数
{
PLIB_USART_TransmitterByteSend(USART_ID_6, chr); //送信バッファーに1バイト書込み・送信
// U6TXREG = chr; ////送信バッファーに1バイト書込み・送信
while (!PLIB_USART_TransmitterIsEmpty(USART_ID_6)); //送信バッファーが空になるまで待つ
……
……
⑦ファイルテーブルFilesTable[ ]の管理番号をインクリメントして次のファイルをオープンする関数です
void DISK_NextTrack(void) //次のファイル曲へ
{
Num_File++;
if(Num_File > (totalFiles -1))Num_File = 1;
DISK_OpenTrack(FilesTable[Num_File].path); //ファイルオープン
}
⑧ファイルをクローズして、LEDを消灯する関数です。
void DISK_CloseTruck (SYS_FS_HANDLE fileHandle)
{
SYS_FS_FileClose ( fileHandle );
ysPlay = 0;
LATGbits.LATG15 = 0; //LED1 消灯
}
⑨ファイルをオープンして LEDを点灯後、ファイル名を取得してキャラクタ液晶に表示しています。
void DISK_OpenTrack ( const char *fname )
{
char tempBuf[16];
ys_fileHandle = SYS_FS_FileOpen(fname, (SYS_FS_FILE_OPEN_READ_PLUS));
//読み込みモードで、ファイルオープン、
ysPlay = 1;
LATGbits.LATG15 = 1; //LED1 点灯
SYS_FS_FileNameGet(ys_fileHandle, str_FileName, 32 ); //ファイル名取得
lcd_cmd(0x80); //1目の先頭へ
sprintf(Buf,"%s ", str_FileName);//
lcd_str(Buf); //液晶表示
lcd_cmd(0xC0); //2行目の先頭へ
sprintf(Buf,"%s ", str_FileName + 16);//str_FileName のポインタを16バイト進める
lcd_str(Buf); // 開始メッセージ1行目表示
}
⑩ファイル名からファイルが8.3形式のファイルか ロングファイル名のファイルかを判別する関数です。
Harmonyの場合 ロングファイル名のファイル名を8.3形式で表示すると先頭から7番目が ~ (0x7E、チルダ)になります。
このことを利用して判別しています。
bool ys_FileType83(char *myFileName) //8.3形式ファイルチェック //8.3形式ならtrue
{
bool Flag;
if(myFileName[6] != 0x7E) Flag = true; //~が含まれない → 8.3形式ファイル名
else Flag = false; //~が含まれる → ロングファイル名 //例:MOONRI~1.mp3
return Flag;
}
⑪DISK_TraverseAllFiles( )関数でこのnod(ディレクトリ)内のファイルを検索して、フルパス付のファイルとしてファイルテーブルFilesTable[
]に 書き込まれます。 SYS_FS_DirOpen( )関数でディレクトリをオープンされます。SYS_FS_DirRead(ys_dirHandle,&ys_dirstat); でファイルや サブディレクトリが1つづつ、順次検索されるので、検索されたファイルやディレクトリのステータスをys_dirstat構造体から読み出します。 ys_dirstat.lfname[0] 及び(ys_dirstat.fname[0] が共に\0(NULL)となった場合すべてが読みだされた場合です。ファイル名の呼び出し方が 異なるので 8.3形式とロングファイル名の場合区別してファイルテーブルに書き込みます。 区別しないですべて8.3形式でテーブルに書き込むと ロングファイル名の7番目が ~ (0x7E、チルダ)になってしまいます。 (totalFiles)++; インクリメントをおこないファイルの数をカウントします。
|
⑫APP_SYSFSEventHandler( )とAPP_USBHostEventHandler( )はUSBマウントに係るコールバック関数で HaarmonyではUSB接続の状態を
チェックする際に必ず使用されます。 USB接続が完了するとSYS_FS_EVENT eventがSYS_FS_EVENT_MOUNTになります。
USB_Connection_Tasks();は 無限循環タスクのAPP_Tasks ( )から常に呼ばれるようにしておき、USBディスクがタスク実行中に
抜かれた場合もプログラムがハングしないようにしておきます。
|
(13) DISK_Tasks( )関数は無限循環タスクのAPP_Tasks ( )から常に呼ばれています。 USBの接続状態を監視して USBディスクが
挿入されたらUSBの初期化などをおこないます。
PICが起動したり、USBディスクが挿入された場合 DISK_TraverseAllFiles( )関数で ルートディレクトリ内のファイルを検索します。
検索した結果として、ファイルの総数 やファイルテーブルFilesTable[ ]から読み出したファイル名をキャラクタ液晶に表示します。
|
(14) ボタンスイッチからの信号により ファイルオープン、クローズ、及びスキップする操作に係る関数です。
bool APP_PlayerCommand (int cmd)
{
switch (cmd)
{
case PLAYER_CMD_STOP:
DISK_CloseTruck(ys_fileHandle);
break;
......
......
以下、 app.c
■ system_interrupt.c に青字部分を追加します。
➀ ファイルオープン、クローズ、スキップを操作するボタンスイッチのイベントフラグの変数です。
extern int BtnEvent[2];
➁ 上記ボタンスイッチがクリックされたことを検出しています。
//Button1 RB0
if(PORTBbits.RB0 == 0) BtnEvent[0] = 1; //入力変化検出 //ファイル open/close
//Button2 RB1
else if(PORTBbits.RB1 == 0) BtnEvent[1] = 1; //入力変化検出 //次のファイル
以下、 system_interrupt.c